package registration;


import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;

import javax.mail.MessagingException;

import org.jasypt.digest.StandardStringDigester;
import org.jasypt.salt.FixedByteArraySaltGenerator;




import DAL.InActiveUserDA;
import DAL.UserDA;
import DAL.UserPassDA;
import encryption.Hash;
import encryption.RSA;
import entities.InActiveUser;
import entities.User;
import entities.UserPass;
import network.Operations;
import network.Server;
import network.ServerConnection;

public class ServerRegistration {
	private ServerConnection connection ;
	private static final int SALT_SIZE = 8;

	/**
	 * Initializes a new instance with the connection with the client
	 * @param conn Connection with the client
	 */
	public ServerRegistration(ServerConnection conn){
		connection = conn;
	}

	/**
	 * Inserts the hashedEmail in the DB in InActiveUsers
	 * @param email
	 * @param hashedEmail
	 * @return true if succeeds
	 */
	private boolean  insertIntoDatabase(String email, String hashedEmail) {
		InActiveUser inActiveUser = new InActiveUser();
		InActiveUserDA inActiveUserDA = new InActiveUserDA();

		inActiveUser.setEmail(email);

		User activeUser = new User();
		UserDA activeUserDA = new UserDA();

		activeUser.setEmail(email);

		int numOfUsers = activeUserDA.selectUsers(activeUser).length;

		if(numOfUsers>0){
			return false;
		}


		InActiveUser[] oldUsers = inActiveUserDA.selectInActiveUsers(inActiveUser);

		inActiveUser.setEmailHash(hashedEmail);

		boolean inserted= false;
		if(oldUsers.length==0)
		{
			inserted = inActiveUserDA.insertInActiveUser(inActiveUser);
		}
		else
		{
			inActiveUser.setId(oldUsers[0].getId());
			inserted = inActiveUserDA.updateInActiveUser(inActiveUser);
		}
		return inserted;
	}

	/**
	 * Inserts Email, password , salt in users table 
	 * @param email
	 * @param password
	 * @param salt
	 */
	private void insertEmailInUsers(String email , String password, byte[] salt) {
		InActiveUser user = new InActiveUser();
		InActiveUserDA userDA = new InActiveUserDA();

		user.setEmail(email);

		userDA.deleteInActiveUser(user);

		User newUser = new User();
		UserDA newUserDA = new UserDA();

		newUser.setEmail(email);

		newUserDA.insertUser(newUser);

		int userID = newUserDA.selectUsers(newUser)[0].getUserID();
		String saltString = Hash.byteToBase64(salt); 

		UserPass newUserPass = new UserPass ();
		UserPassDA newUserPassDA = new UserPassDA();

		newUserPass.setUserID(userID);
		newUserPass.setPasswordHash(password);
		newUserPass.setSalt(saltString);
		newUserPassDA.insertUserPass(newUserPass);
	}
	
	/**
	 * Selects the users with the same hash and returns the email
	 * @param emailHash
	 * @return email
	 */
	private String getEmailFromHash(String emailHash) {
		InActiveUser user = new InActiveUser();
		InActiveUserDA userDA = new InActiveUserDA();

		user.setEmailHash(emailHash);

		InActiveUser [] users = userDA.selectInActiveUsers(user);

		if(users.length==0){
			return "";
		}

		return users[0].getEmail();
	}
	
	/**
	 * Hashes the email with a random salt
	 * @param email
	 * @return hashed email
	 */
	private String hashEmail(String email)
	{
		StandardStringDigester digest = new StandardStringDigester();

		SecureRandom random = new SecureRandom();		
		byte[] salt = random.generateSeed(SALT_SIZE);
		FixedByteArraySaltGenerator saltGenerator = new FixedByteArraySaltGenerator();

		saltGenerator.setSalt(salt);
		digest.setSaltGenerator(saltGenerator);
		String hashedEmail = digest.digest(email);


		return hashedEmail;
	}

	/**
	 * Adds email into InactiveUsers and send email to user
	 * @param email
	 */
	public void register(){
		connection.sendMessage("Start registering");
		
		String receivedMessageEncrypted = null;
		try {
			receivedMessageEncrypted = new String(connection.receiveRSAMessage() , "ISO-8859-1");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			connection.sendMessage(""+ Operations.REGISTERATION_FAILED);
			return;
		}
		
		String email = new RSA().rsadecrypt(receivedMessageEncrypted, Server.privateKeyMod, Server.privateKetExp);
		
		String hashedEmail = hashEmail(email);
		boolean inserted = insertIntoDatabase(email, hashedEmail);
		if(!inserted)
		{
			connection.sendMessage(""+ Operations.REGISTERATION_FAILED);
			return;
		}
		String emailText = "Dear " + email + "\n"
		+ "Please copy the following activation code and paste it in the program \n"
		+ hashedEmail ;


		Emailer emailer = new Emailer(email , 

				"Activating Instructions" , emailText );
		Thread thread = new Thread(emailer);
		thread.start();
		
		System.out.println("Sucessfully Sent mail");
		connection.sendMessage(""+ Operations.REGISTRATION_COMPLETE);
	}

	/**
	 * Activates the user by receiving the hashed email and the password
	 * @param hashedEmail
	 */
	public void activate(){
		
		connection.sendMessage("starting activation");
		String receivedMessageEncrypted = null;
		try {
			receivedMessageEncrypted = new String(connection.receiveRSAMessage() , "ISO-8859-1");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		String recievedMessage = new RSA().rsadecrypt(receivedMessageEncrypted, Server.privateKeyMod, Server.privateKetExp);
		
		String hashedEmail = recievedMessage.split(" ")[0];
		String randomPassword = recievedMessage.split(" ")[1];
		String emailAfterActivation = getEmailFromHash(hashedEmail);
		
		if(!emailAfterActivation.equals(""))
		{
			System.out.println("Account is activated..Waiting for password: ");
			String message = Operations.ACTIVATE_COMPLETE + " ";

			SecureRandom random = new SecureRandom();		
			byte[] salt = random.generateSeed(SALT_SIZE);
			message += Hash.byteToBase64(salt);
			connection.sendMessage(message);
			
			String receivedMessage2Encrypted = null;
			try {
				receivedMessage2Encrypted = new String(connection.receiveRSAMessage() ,"ISO-8859-1");
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			String receivedMessage2 = new RSA().rsadecrypt(receivedMessage2Encrypted, Server.privateKeyMod, Server.privateKetExp);
			
			if(receivedMessage2.split(" ").length != 2){
				connection.sendMessage("" + Operations.ACTIVATE_FAILED);
				return;
			}
			if(!receivedMessage2.split(" ")[1].equals(randomPassword)){
				connection.sendMessage("" + Operations.ACTIVATE_FAILED);
				return;
			}
			String password = receivedMessage2.split(" ")[0];
			insertEmailInUsers(emailAfterActivation , password , salt);
		}
		else
		{
			System.out.println("Wrong activation code");
			connection.sendMessage("" + Operations.ACTIVATE_FAILED);
		}
	}
}
